// Helper for connection operations.

#include "ConnectionManager.h"
#include "Common.h"
#include "BitHelper.h"
#include <iostream>

// Construct a ConnectionManager with the given options.
ConnectionManager::ConnectionManager(ConnectionOptions& connectionOptions)
{
	m_connectionOptions = connectionOptions;
}

#include <locale.h>
// Get the connection information.
bool ConnectionManager::GetConnectionInformations(ConnectionInformations& connectionInformations)
{
	TcpHelper tcpHelper(__DEFAULT_ADDRESS__, __DEFAULT_PORT__);
	
	// try to connect
	return tcpHelper.TryConnect() &&
		
		// check the packet Id, then read the server address, server port, client version, update address and client address
		CheckPacketId(tcpHelper, 0) && tcpHelper.TryRead(connectionInformations.Address) && tcpHelper.TryRead(connectionInformations.Port) && tcpHelper.TryRead(connectionInformations.RequiredVersion) && 
		tcpHelper.TryRead(connectionInformations.UpdateAddress) && tcpHelper.TryRead(connectionInformations.ClientAddress) &&
		
		// try to disconnect
		tcpHelper.TryDisconnect();
}

// Get the authorization.
bool ConnectionManager::GetAuthorization(ConnectionInformations& connectionInformations, Authorization& authorization)
{
	unsigned int randomNumber;
	TcpHelper tcpHelper(connectionInformations.Address, to_string(connectionInformations.Port));

	// try to connect, send the user name, read the random number, send the informations, then
	return tcpHelper.TryConnect() && 
		
		// send the hand shake
		SendHandShake(tcpHelper) && 
		
		// read the random number
		ReadRandomNumber(tcpHelper, randomNumber) && 
		
		// send the informations
		SendInformations(tcpHelper, connectionInformations.ClientAddress, randomNumber) && 
		
		// read the authorization
		ReadAuthorization(tcpHelper, authorization) &&
		
		// try to disconnect
		tcpHelper.TryDisconnect();
}

// Send the handshake.
bool ConnectionManager::SendHandShake(TcpHelper& tcpHelper)
{
	vector<char> buffer;
	byte packetId = 1;
	BitHelper::Add(buffer, packetId);
	BitHelper::Add(buffer, m_connectionOptions.UserName);
	return tcpHelper.TrySend(buffer);
}

// Read the random number.
bool ConnectionManager::ReadRandomNumber(TcpHelper& tcpHelper, unsigned int& randomNumber)
{
	return CheckPacketId(tcpHelper, 2) && tcpHelper.TryRead(randomNumber);
}

// Send the informations.
bool ConnectionManager::SendInformations(TcpHelper& tcpHelper, const string& clientAddress, const unsigned int& randomNumber)
{
	vector<char> buffer;
	byte packetId = 3;
	string encryptedKey = BitHelper::Encrypt(m_connectionOptions.UserKey, randomNumber);
	BitHelper::Add(buffer, packetId);
	BitHelper::Add(buffer, encryptedKey);
	BitHelper::Add(buffer, clientAddress);
	return tcpHelper.TrySend(buffer);
}

// Read the authorization.
bool ConnectionManager::ReadAuthorization(TcpHelper& tcpHelper, Authorization& authorization)
{
	int status;
	return CheckPacketId(tcpHelper, 4) && tcpHelper.TryRead(status) && (authorization.Status = static_cast<Status>(status)) != Status::None && tcpHelper.TryRead(authorization.NewKey) && tcpHelper.TryRead(authorization.Duration);
}

// Check the packet Id.
bool ConnectionManager::CheckPacketId(TcpHelper& tcpHelper, const TCHAR packetId)
{
	byte readPacketId;
	if (!tcpHelper.TryRead(readPacketId)) return false;
	if (packetId != readPacketId) return LogManager::DisplayWarning(L"Communication error : unexcepted packet with id %c.\n", readPacketId);
	return true;
}